package fr.asip.cps3.exemple.modele.traitements.fonctionsPKCS11.slotscartes;

import iaik.pkcs.pkcs11.wrapper.CK_TOKEN_INFO;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import java.util.LinkedHashMap;

import org.apache.log4j.Logger;

import fr.asip.cps3.exemple.modele.exceptions.ExceptionProgrammeExemple;
import fr.asip.cps3.exemple.modele.exceptions.ExceptionTraitement;
import fr.asip.cps3.exemple.modele.resultats.Resultat;
import fr.asip.cps3.exemple.modele.resultats.ResultatInfo;
import fr.asip.cps3.exemple.modele.traitements.util.TraitementsUtil;

/**
 * Classe de traitement : Obtention des informations sur la carte
 *
 */
public class InfoToken{

	/**
	 * Le loggeur
	 */
	private static Logger log = Logger.getLogger(InfoToken.class);
	
	/**
	 * Renvoie le résultat de l'opération
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @param idSlotToken Identifiant du slot hébergeant le token
	 * @return Résultat de l'opération
	 * @throws ExceptionTraitement 
	 */
	public static Resultat traitementP11(PKCS11 librairie, long idSlotToken) throws ExceptionTraitement {


		try {
		
			if(librairie != null) {
		
				ResultatInfo resultat = new ResultatInfo("Obtenir des informations sur la carte ");
				LinkedHashMap<String,String> infos = new LinkedHashMap<String,String>();
				resultat.setInfos(infos);
		
				// Récupération des informations sur le token
				try {
					
					if(resultat != null) {
						
						// Traitement à tester
						CK_TOKEN_INFO info = librairie.C_GetTokenInfo(idSlotToken);
			
						if(info != null) {
			
							resultat.appendTraitement(new String(info.label).trim()+" (C_GetTokenInfo)");
							infos.put("Libellé application attribué lors de l'initialisation de la carte",new String(info.label).trim());
							infos.put("Identifiant du fabricant de la carte",new String(info.manufacturerID));
							infos.put("Modèle de la carte",new String(info.model));
							infos.put("Numéro de série de la carte",new String(info.serialNumber));
							infos.put("Nombre maximum de sessions pouvant être ouvertes simultanément par une même application sur la carte",Long.toString(info.ulMaxSessionCount));
							infos.put("Nombre de sessions que l'application courante a d'ouvertes sur la carte",Long.toString(info.ulSessionCount));
							infos.put("Nombre maximum de sessions en lecture/écriture pouvant être ouvertes simultanément par une même application sur la carte",Long.toString(info.ulMaxRwSessionCount));
							infos.put("Nombre de sessions en lecture/écriture que l'application courante a d'ouvertes sur la carte",Long.toString(info.ulRwSessionCount));
							infos.put("Longueur maximale (en octets) du code porteur",Long.toString(info.ulMaxPinLen));
							infos.put("Longueur minimale (en octets) du code porteur",Long.toString(info.ulMinPinLen));
							infos.put("Capacité mémoire totale (en octets) pour le stockage d'objets publics",Long.toString(info.ulTotalPublicMemory));			
							infos.put("Espace mémoire disponible (en octets) pour le stockage d'objets publics",Long.toString(info.ulFreePublicMemory));
							infos.put("Capacité mémoire totale (en octets) pour le stockage d'objets privés",Long.toString(info.ulTotalPrivateMemory));
							infos.put("Espace mémoire disponible (en octets) pour le stockage d'objets privés",Long.toString(info.ulFreePrivateMemory));
							infos.put("Numéro de version matérielle de la carte",info.hardwareVersion.toString());
							infos.put("Numéro de version firmware de la carte",info.firmwareVersion.toString());
							if(new String(info.utcTime).toString().trim().length() != 0)
								infos.put("Date de la carte",new String(info.utcTime));
							else
								infos.put("Date de la carte","indisponible");
							infos.put("La carte a son propre générateur de nombre aléatoire?",(info.flags & PKCS11Constants.CKF_RNG)!=0?"Oui":"Non");			
							infos.put("La carte est-elle protégée en écriture?",(info.flags & PKCS11Constants.CKF_WRITE_PROTECTED)!=0?"Oui":"Non");
							infos.put("La carte nécessite-t-elle une authentification?",(info.flags & PKCS11Constants.CKF_LOGIN_REQUIRED)!=0?"Oui":"Non");
							infos.put("Le code porteur de l'utilisateur est-il initialisé?",(info.flags & PKCS11Constants.CKF_USER_PIN_INITIALIZED)!=0?"Oui":"Non");
							infos.put("La sauvegarde réussie de l'état d'une opération cryptographique de session contient-elle toutes les clés nécessaires pour rétablir l'état de la session?",(info.flags & PKCS11Constants.CKF_RESTORE_KEY_NOT_NEEDED)!=0?"Oui":"Non");
							infos.put("La carte possède-t-elle une horloge?",(info.flags & PKCS11Constants.CKF_CLOCK_ON_TOKEN)!=0?"Oui":"Non");
							infos.put("La carte a-t-elle un mode d'authentification protégé par où l'utilisateur peut s'authentifier sans passer de code porteur au travers d'une bibliothèque cryptographique?",(info.flags & PKCS11Constants.CKF_PROTECTED_AUTHENTICATION_PATH)!=0?"Oui":"Non");
							infos.put("La carte permet-elle l'exécution d'opérations cryptographiques \"dual\" lors d'une même session?",(info.flags & PKCS11Constants.CKF_DUAL_CRYPTO_OPERATIONS)!=0?"Oui":"Non");
							infos.put("La carte est-elle initialisée?",(info.flags & PKCS11Constants.CKF_TOKEN_INITIALIZED)!=0?"Oui":"Non");
							infos.put("Un code porteur utilisateur incorrect a-t-il été saisi au moins une fois depuis la dernière authentification utilisateur réussie?",(info.flags & PKCS11Constants.CKF_USER_PIN_COUNT_LOW)!=0?"Oui":"Non");
							infos.put("La prochaine saisie d'un code porteur utilisateur incorrect provoquera-t-elle le blocage du token?",(info.flags & PKCS11Constants.CKF_USER_PIN_FINAL_TRY)!=0?"Oui":"Non");
							infos.put("Le code porteur utilisateur est-il bloqué?",(info.flags & PKCS11Constants.CKF_USER_PIN_LOCKED)!=0?"Oui":"Non");
							infos.put("Le code porteur utilisateur doit-il être changé?",(info.flags & PKCS11Constants.CKF_USER_PIN_TO_BE_CHANGED)!=0?"Oui":"Non");
							infos.put("Un code porteur Security Officer(SO) incorrect a-t-il été saisi au moins une fois depuis la dernière authentification SO réussie?",(info.flags & PKCS11Constants.CKF_SO_PIN_COUNT_LOW)!=0?"Oui":"Non");
							infos.put("La prochaine saisie d'un code porteur SO incorrect provoquera-t-elle le blocage de la carte?",(info.flags & PKCS11Constants.CKF_SO_PIN_FINAL_TRY)!=0?"Oui":"Non");
							infos.put("Le code porteur SO est-il bloqué?",(info.flags & PKCS11Constants.CKF_SO_PIN_LOCKED)!=0?"Oui":"Non");
							infos.put("Le code porteur SO doit-il être changé?",(info.flags & PKCS11Constants.CKF_SO_PIN_TO_BE_CHANGED)!=0?"Oui":"Non");
							
						} else {
							
							resultat.appendTraitement("(C_GetTokenInfo)");
							
							// Si les informations sont nulles on lève l'exception
							log.error("L'operation a retourne des informations nulles");
							throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_INFO_CARTE, "L'opération a retourné des informations nulles");
							
						}
					}
					
				} catch (PKCS11Exception e) {
					
					log.info("Operation echouee : "+TraitementsUtil.retranscritCodeRetour(e.getErrorCode()));
					resultat.setCodeRetour(e.getErrorCode());
					
				}
		
				return resultat;
				
			} else {
	
				// Si la librairie est nulle il est impossible de réaliser l'opération
				log.error("La librairie est nulle");
				throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_INFO_CARTE, "La librairie est nulle");
				
			}
			
		} catch (Throwable t) {
			
			// Si une erreur Traitement a été rencontrée on lève l'exception
			if(t instanceof ExceptionTraitement)
				throw (ExceptionTraitement)t;
			
			// Si une erreur inattendue est survenue on la logue et on la lève
			log.error("Une erreur inattendue est survenue : "+ExceptionProgrammeExemple.getStacktrace(t));
			throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_INFO_CARTE, "Une erreur inattendue est survenue");
			
		}
	}

}
